home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir37 / ms_sh23s.zip / SRC / SH10.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  47KB  |  2,122 lines

  1. /*
  2.  * MS-DOS SHELL - Function Processing
  3.  *
  4.  * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited
  5.  *
  6.  * This code is subject to the following copyright restrictions:
  7.  *
  8.  * 1.  Redistribution and use in source and binary forms are permitted
  9.  *     provided that the above copyright notice is duplicated in the
  10.  *     source form and the copyright notice in file sh6.c is displayed
  11.  *     on entry to the program.
  12.  *
  13.  * 2.  The sources (or parts thereof) or objects generated from the sources
  14.  *     (or parts of sources) cannot be sold under any circumstances.
  15.  *
  16.  * Note:  1.  The PrintProcessTree code is based on code written by Kai Uwe
  17.  *          Rommel
  18.  *
  19.  *      2.  When parts of the original 2.1 shell were replaced by the Lexical
  20.  *          Analsyer written by Simon J. Gerraty (for his Public Domain Korn
  21.  *          Shell, which is also based on Charles Forsyth original idea), a
  22.  *          number of changes were made to reflect the changes Simon made to
  23.  *          the Parse output tree.  Some parts of this code in this module
  24.  *          are based on the algorithms/ideas that he incorporated into his
  25.  *          shell, in particular the Function Processing functions.
  26.  *
  27.  *    $Header: /usr/users/istewart/shell/sh2.3/Release/RCS/sh10.c,v 2.15 1994/08/25 20:49:11 istewart Exp $
  28.  *
  29.  *    $Log: sh10.c,v $
  30.  *    Revision 2.15  1994/08/25  20:49:11  istewart
  31.  *    MS Shell 2.3 Release
  32.  *
  33.  *    Revision 2.14  1994/02/23  09:23:38  istewart
  34.  *    Beta 233 updates
  35.  *
  36.  *    Revision 2.13  1994/02/01  10:25:20  istewart
  37.  *    Release 2.3 Beta 2, including first NT port
  38.  *
  39.  *    Revision 2.12  1994/01/11  17:55:25  istewart
  40.  *    Release 2.3 Beta 0 patches
  41.  *
  42.  *    Revision 2.11  1993/12/01  11:58:34  istewart
  43.  *    Release 226 beta
  44.  *
  45.  *    Revision 2.10  1993/08/25  16:03:57  istewart
  46.  *    Beta 225 - see Notes file
  47.  *
  48.  *    Revision 2.9  1993/07/02  10:21:35  istewart
  49.  *    224 Beta fixes
  50.  *
  51.  *    Revision 2.8  1993/06/14  11:01:44  istewart
  52.  *    More changes for 223 beta
  53.  *
  54.  *    Revision 2.7  1993/06/02  09:52:35  istewart
  55.  *    Beta 223 Updates - see Notes file
  56.  *
  57.  *    Revision 2.6  1993/02/16  16:03:15  istewart
  58.  *    Beta 2.22 Release
  59.  *
  60.  *    Revision 2.5  1993/01/26  18:35:09  istewart
  61.  *    Release 2.2 beta 0
  62.  *
  63.  *    Revision 2.4  1992/12/14  10:54:56  istewart
  64.  *    BETA 215 Fixes and 2.1 Release
  65.  *
  66.  *    Revision 2.3  1992/11/06  10:03:44  istewart
  67.  *    214 Beta test updates
  68.  *
  69.  *    Revision 2.2  1992/07/16  14:33:34  istewart
  70.  *    Beta 212 Baseline
  71.  *
  72.  *    Revision 2.1  1992/07/10  10:52:48  istewart
  73.  *    211 Beta updates
  74.  *
  75.  *    Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
  76.  *    MS-Shell 2.0 Baseline release
  77.  *
  78.  */
  79.  
  80. #include <sys/types.h>
  81. #include <sys/stat.h>
  82. #include <stdio.h>
  83. #include <signal.h>
  84. #include <errno.h>
  85. #include <setjmp.h>
  86. #include <ctype.h>
  87. #include <string.h>
  88. #include <unistd.h>
  89. #include <stdlib.h>
  90. #include <fcntl.h>
  91. #include <limits.h>
  92. #include <dirent.h>
  93. #include "sh.h"
  94.  
  95. #if (OS_TYPE == OS_UNIX)
  96. #  include <sys/times.h>
  97. #endif 
  98.  
  99. /* Function declarations */
  100.  
  101. static void F_LOCAL    PrintCommand (C_Op *, int);
  102. static void F_LOCAL    PrintIOInformation (IO_Actions *);
  103. static void F_LOCAL    PrintCaseCommand (C_Op *);
  104. static void F_LOCAL    PrintIndentedString (char *, int, int);
  105. static void F_LOCAL    PrintVarArg (unsigned char *);
  106. static void F_LOCAL    fputMagicChar (unsigned int);
  107. static void F_LOCAL    PrintMode (int);
  108.  
  109. static void F_LOCAL    SaveReleaseExecuteTree (C_Op *, void (*)(void *));
  110. static void F_LOCAL    SaveReleaseWordList (char **, void (*)(void *));
  111. static void F_LOCAL    SaveReleaseIOActions (IO_Actions **, void (*)(void *));
  112. static void        SaveTreeEntry (void *);
  113.  
  114. static C_Op *    F_LOCAL    DuplicateFunctionTree (C_Op *);
  115. static char **  F_LOCAL    DuplicateWordList (char **list);
  116. static IO_Actions ** F_LOCAL DuplicateIOActions (IO_Actions **);
  117.  
  118. static int        FindFunction (const void *, const void *);
  119. static int        SearchFunction (const void *, const void *);
  120. static void        DisplayFunction (const void *, VISIT, int);
  121. static void        DeleteAFunction (const void *, VISIT, int);
  122.  
  123. static int        FindAlias (const void *, const void *);
  124. static int        SearchAlias (const void *, const void *);
  125. static void        UntrackAlias (const void *, VISIT, int);
  126. static void        DisplayAlias (const void *, VISIT, int);
  127.  
  128. #if (OS_TYPE != OS_DOS)
  129. static void        DisplayJob (const void *, VISIT, int);
  130. static void        CountJob (const void *, VISIT, int);
  131. static int        SearchJob (const void *, const void *);
  132. static int        FindJob (const void *, const void *);
  133. static void        FindJobByString (const void *, VISIT, int);
  134. static int        FindJobByPID (const void *, const void *);
  135. static int        FindJobBySession (const void *, const void *);
  136. #endif
  137.  
  138. #if (OS_TYPE == OS_OS2)
  139. #  if (OS_SIZE == OS_32)
  140. #    if !defined (__EMX__)
  141. #      define Dos32GetPrty    DosGetPrty
  142. #      define Dos32QProcStatus    DosQProcStatus
  143. #      pragma linkage (DosQProcStatus, far16 pascal)
  144. #      pragma linkage (DosGetPrty, far16 pascal)
  145. #    else
  146. USHORT _THUNK_FUNCTION (Dos16GetPrty) ();
  147. USHORT _THUNK_FUNCTION (Dos16QProcStatus) ();
  148. #    endif
  149. extern USHORT            Dos32QProcStatus (PVOID, USHORT);
  150. extern USHORT            Dos32GetPrty (USHORT, PUSHORT, USHORT);
  151. #  else
  152. #    define Dos32QProcStatus    DosQProcStatus
  153. #    define Dos32GetPrty    DosGetPrty
  154. extern USHORT APIENTRY        Dos32QProcStatus (PVOID, USHORT);
  155. #  endif
  156. #endif
  157.  
  158. /*
  159.  * OS/2 Process Information structures
  160.  *
  161.  *
  162.  * Declare OS2 1.x 16-bit version structures
  163.  */
  164.  
  165. #if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_16)
  166. typedef struct process
  167. {
  168.     USHORT    pid;
  169.     USHORT    ppid;
  170.     USHORT    threads;
  171.     USHORT    children;
  172.     USHORT    modhandle;
  173.     USHORT    module;
  174. } V1Process_t;
  175.  
  176. typedef struct module
  177. {
  178.     USHORT    modhandle;
  179.     USHORT    max_dependents;
  180.     USHORT    *dependents;
  181.     UCHAR    *modname;
  182. } V1Module_t;
  183.  
  184. typedef struct ProcessInfo
  185. {
  186.     V1Process_t        **V1Processes;
  187.     V1Module_t        **V1Modules;
  188.     USHORT        M_Processes;
  189.     USHORT        N_Processes;
  190.     USHORT        M_Modules;
  191.     USHORT        N_Modules;
  192. } V1ProcessStatus_t;
  193. #endif
  194.  
  195. /*
  196.  * OS2 2.0 - 32 Bit version structures
  197.  */
  198.  
  199. #if (OS_TYPE == OS_OS2)
  200. #  if (OS_SIZE == OS_32)
  201. #    define PTR(ptr)    (ptr)
  202. #  else
  203. #    define PTR(ptr)    ((void *)((((ULONG)ps)     & 0xFFFF0000L) |    \
  204.                   (((ULONG)(ptr))  & 0x0000FFFFL) ))
  205. #  endif
  206.  
  207. #  define PROCESS_END_INDICATOR    3
  208.  
  209. /* Process Status structures */
  210.  
  211. #  if (OS_SIZE == OS_32)
  212. #    pragma pack(1)
  213. #  endif
  214.  
  215. /*
  216.  * Thread Info
  217.  */
  218.  
  219. typedef struct thread2
  220. {
  221.     ULONG    ulRecType;        /* Record type (thread = 100)    */
  222.     USHORT    tidWithinProcess;    /* TID within process (TID is    */
  223.                         /* 4 bytes!!)            */
  224.     USHORT    usSlot;            /* Unique thread slot number    */
  225.     ULONG    ulBlockId;        /* Sleep id thread is sleeping on*/
  226.     ULONG    ulPriority;        /* Priority            */
  227.     ULONG    ulSysTime;        /* Thread System Time        */
  228.     ULONG    ulUserTime;        /* Thread User Time        */
  229.     UCHAR    uchState;        /* 1=ready,2=blocked,5=running    */
  230.     UCHAR    uchPad;            /* Filler            */
  231.     USHORT    usPad;            /* Filler            */
  232. } V2Thread_t;
  233.  
  234. /*
  235.  * Process Information
  236.  */
  237.  
  238. typedef struct process2
  239. {
  240.     ULONG    ulEndIndicator;        /* 1 means not end, 3 means    */
  241.                         /* last entry            */
  242.     V2Thread_t    *ptiFirst;        /* Address of the 1st Thread    */
  243.                         /* Control Blk            */
  244.     USHORT    pid;            /* Process ID (2 bytes - PID    */
  245.                         /* is 4 bytes)            */
  246.     USHORT    pidParent;        /* Parent's process ID        */
  247.     ULONG    ulType;            /* Process Type            */
  248.     ULONG    ulStatus;        /* Process Status        */
  249.     ULONG    idSession;        /* Session ID            */
  250.     USHORT    hModRef;        /* Module handle of EXE        */
  251.     USHORT    usThreadCount;        /* Number of threads in this    */
  252.                         /* process            */
  253.     ULONG    ulSessionType;        /* Session Type            */
  254.     PVOID    pvReserved;        /* Unknown            */
  255.     USHORT    usSem16Count;        /* Number of 16-bit system    */
  256.                         /* semaphores            */
  257.     USHORT    usDllCount;        /* Number of Dlls used by    */
  258.                         /* process            */
  259.     USHORT    usShrMemHandles;    /* Number of shared memory    */
  260.                         /* handles            */
  261.     USHORT    usReserved;        /* Unknown            */
  262.     PUSHORT    pusSem16TableAddr;    /* Address of a 16-bit semaphore*/
  263.                         /* table            */
  264.     PUSHORT    pusDllTableAddr;    /* Address of a Dll table    */
  265.     PUSHORT    pusShrMemTableAddr;    /* Address of a shared memory    */
  266.                         /* table            */
  267. } V2Process_t;
  268.  
  269. /*
  270.  * Process Status header
  271.  */
  272.  
  273. typedef struct processstatus2
  274. {
  275.     PVOID    psumm;        /* SUMMARY section ptr            */
  276.     V2Process_t    *ppi;        /* PROCESS section ptr            */
  277.     PVOID    psi;        /* SEM section ptr (add 16 to offset)    */
  278.     PVOID    pDontKnow1;    /*                    */
  279.     PVOID    psmi;        /* SHARED MEMORY section ptr        */
  280.     PVOID    pmi;        /* MODULE section ptr            */
  281.     PVOID    pDontKnow2;    /*                    */
  282.     PVOID    pDontKnow3;    /*                    */
  283. } V2ProcessStatus_t;
  284.  
  285. #  if (OS_SIZE == OS_32)
  286. #    pragma pack()
  287. #  endif
  288. #endif
  289.  
  290. /*
  291.  * Associated functions
  292.  */
  293.  
  294. #if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_16)
  295. static int            SortV1Processes (void *, void *);
  296. static void F_LOCAL        PrintV1ProcessTree (pid_t, int,
  297.                             V1ProcessStatus_t *);
  298. static bool F_LOCAL        Parse_V1ProcessTable (UCHAR *,
  299.                               V1ProcessStatus_t *);
  300. #endif
  301.  
  302. #if (OS_TYPE == OS_OS2)
  303. static void F_LOCAL        V2_DisplayProcessTree (USHORT, USHORT,
  304.                                V2ProcessStatus_t *);
  305. static V2ProcessStatus_t * F_LOCAL GetProcessStatus (char *);
  306. #endif
  307.  
  308. #if (OS_TYPE != OS_DOS)
  309. static char    *JobSearchKey;        /* Job search string        */
  310. static int    NumberOfJobs = 0;    /* Number of Jobs        */
  311. static JobList    **JobSearchEntry;    /* Matching entry        */
  312. #endif
  313.  
  314. static bool    DisplayListMode = FALSE;/* Mode for Display Job/Alias    */
  315. static int    Print_indent;        /* Current indent level        */
  316.  
  317.                     /* IO types            */
  318. static char    *IOTypes [] = { "<", ">", "<>", "<<", ">>", ">&" };
  319.  
  320. /*
  321.  * Duplicate a memory area
  322.  */
  323.  
  324. #define DuplicateMemoryArea(area, type)                    \
  325.         (type)((area == (void *)NULL)                \
  326.             ? (void *)NULL                    \
  327.             : DuplicateMemoryCell (area))
  328.  
  329. /*
  330.  * Print ALL functions
  331.  */
  332.  
  333. int PrintAllFunctions (void)
  334. {
  335.     twalk (FunctionTree, DisplayFunction);
  336.     return 0;
  337. }
  338.  
  339. /*
  340.  * TWALK function to display the JOB, FUNCTION and ALIAS trees
  341.  */
  342.  
  343. #if (OS_TYPE != OS_DOS)
  344. static void CountJob (const void *key, VISIT visit, int level)
  345. {
  346.     if ((visit == postorder) || (visit == leaf))
  347.     NumberOfJobs++;
  348. }
  349.  
  350. static void DisplayJob (const void *key, VISIT visit, int level)
  351. {
  352.     if ((visit == postorder) || (visit == leaf))
  353.     {
  354.     printf ("[%d] %c", (*(JobList **)key)->Number,
  355.         ((*(JobList **)key)->Number == CurrentJob)
  356.             ? CHAR_PLUS
  357.             : (((*(JobList **)key)->Number == PreviousJob)
  358.                 ? CHAR_HYPHEN : CHAR_SPACE));
  359.  
  360.     if (DisplayListMode)
  361.         printf (" %d", (*(JobList **)key)->pid);
  362.  
  363.     fputchar (CHAR_TAB);
  364.     FlushStreams ();
  365.     DisplayLineWithControl ((*(JobList **)key)->Command);
  366.     fputchar (CHAR_NEW_LINE);
  367.     }
  368. }
  369. #endif
  370.  
  371. static void DisplayFunction (const void *key, VISIT visit, int level)
  372. {
  373.     if ((visit == postorder) || (visit == leaf))
  374.         PrintFunction ((*(FunctionList **)key)->tree, PF_MODE_NORMAL);
  375.  
  376. }
  377.  
  378. static void DisplayAlias (const void *key, VISIT visit, int level)
  379. {
  380.     if (((visit == postorder) || (visit == leaf)) &&
  381.     (!DisplayListMode || (*(AliasList **)key)->AFlags & ALIAS_TRACKED))
  382.     PrintAlias ((*(AliasList **)key)->name);
  383. }
  384.  
  385.  
  386. /*
  387.  * DISPLAY A FUNCTION TREE
  388.  */
  389.  
  390. /*
  391.  * print the execute tree - used for displaying functions
  392.  */
  393.  
  394. void PrintFunction (register C_Op *t, int mode)
  395. {
  396.     char        **wp;
  397.  
  398.     if (t == (C_Op *)NULL)
  399.     return;
  400.  
  401. /* Check for start of print */
  402.  
  403.     if (t->type == TFUNC)
  404.     {
  405.     Print_indent = 0;
  406.     printf (LIT_2Strings, t->str, "()");
  407.     PrintFunction (t->left, PF_MODE_NORMAL);
  408.     FlushStreams ();
  409.     return;
  410.     }
  411.  
  412. /* Otherwise, process the tree and print it */
  413.  
  414.     switch (t->type)
  415.     {
  416.     case TASYNC:            /* Asyn commands        */
  417.         PrintFunction (t->left, PF_MODE_ASYNC);
  418.         return;
  419.  
  420.     case TCOPROCESS:        /* Co-process            */
  421.         PrintFunction (t->left, PF_MODE_COPROC);
  422.         return;
  423.  
  424.     case TPAREN:            /* ()                */
  425.     case TCOM:            /* A command process        */
  426.         PrintCommand (t, mode);
  427.         return;
  428.  
  429.     case TPIPE:            /* Pipe processing        */
  430.         PrintFunction (t->left, PF_MODE_NORMAL);
  431.         PrintIndentedString ("|\n", 0, PF_MODE_NORMAL);
  432.         PrintFunction (t->right, mode);
  433.         return;
  434.  
  435.     case TLIST:            /* Entries in a for statement    */
  436.         PrintFunction (t->left, PF_MODE_NORMAL);
  437.         PrintFunction (t->right, mode);
  438.         return;
  439.  
  440.     case TOR:            /* || and &&            */
  441.     case TAND:
  442.         PrintFunction (t->left, PF_MODE_NORMAL);
  443.  
  444.         if (t->right != (C_Op *)NULL)
  445.         {
  446.         PrintIndentedString ((t->type == TAND) ? "&&\n" : "||\n",
  447.                      0, PF_MODE_NORMAL);
  448.         PrintFunction (t->right, mode);
  449.         }
  450.  
  451.         return;
  452.  
  453.     case TFOR:            /* First part of a for statement*/
  454.     case TSELECT:
  455.         PrintIndentedString ((t->type == TFOR) ? "for " : "select ",
  456.                  0, PF_MODE_NORMAL);
  457.         foputs (t->str);
  458.  
  459.         if ((wp = t->vars) != NOWORDS)
  460.         {
  461.         foputs (" in");
  462.  
  463.         while (*wp != NOWORD)
  464.         {
  465.             fputchar (CHAR_SPACE);
  466.             PrintVarArg ((unsigned char *)*(wp++));
  467.         }
  468.         }
  469.  
  470.         fputchar (CHAR_NEW_LINE);
  471.         PrintIndentedString ("do\n", 1, PF_MODE_NORMAL);
  472.         PrintFunction (t->left, PF_MODE_NORMAL);
  473.         PrintIndentedString (LIT_done, -1, mode);
  474.         return;
  475.  
  476.     case TWHILE:            /* WHILE and UNTIL functions    */
  477.     case TUNTIL:
  478.         PrintIndentedString ((t->type == TWHILE) ? "while\n" : "until\n",
  479.                  1, PF_MODE_NORMAL);
  480.         PrintFunction (t->left, PF_MODE_NORMAL);
  481.         Print_indent--;
  482.         PrintIndentedString ("do\n", 1, PF_MODE_NORMAL);
  483.         PrintFunction (t->right, PF_MODE_NORMAL);
  484.         PrintIndentedString (LIT_done, -1, mode);
  485.         return;
  486.  
  487.     case TIF:            /* IF and ELSE IF functions    */
  488.     case TELIF:
  489.         if (t->type == TIF)
  490.         PrintIndentedString ("if\n", 1, PF_MODE_NORMAL);
  491.  
  492.         else
  493.         PrintIndentedString ("elif\n", 1, PF_MODE_NORMAL);
  494.  
  495.         PrintFunction (t->left, PF_MODE_NORMAL);
  496.  
  497.         if (t->right != (C_Op *)NULL)
  498.         {
  499.         Print_indent -= 1;
  500.         PrintIndentedString ("then\n", 1, PF_MODE_NORMAL);
  501.         PrintFunction (t->right->left, PF_MODE_NORMAL);
  502.  
  503.         if (t->right->right != (C_Op *)NULL)
  504.         {
  505.             Print_indent -= 1;
  506.  
  507.             if (t->right->right->type != TELIF)
  508.             PrintIndentedString ("else\n", 1, PF_MODE_NORMAL);
  509.  
  510.             PrintFunction (t->right->right, PF_MODE_NORMAL);
  511.         }
  512.         }
  513.  
  514.         if (t->type == TIF)
  515.         PrintIndentedString ("fi", -1, mode);
  516.  
  517.         return;
  518.  
  519.     case TCASE:            /* CASE function        */
  520.         PrintIndentedString ("case ", 1, PF_MODE_NORMAL);
  521.         PrintVarArg ((unsigned char *)t->str);
  522.         puts (" in");
  523.         PrintCaseCommand (t->left);
  524.         PrintIndentedString ("esac", -1, mode);
  525.         return;
  526.  
  527.     case TBRACE:            /* {} statement            */
  528.         PrintIndentedString ("{\n", 1, PF_MODE_NORMAL);
  529.         if (t->left != (C_Op *)NULL)
  530.         PrintFunction (t->left, mode);
  531.  
  532.         PrintIndentedString ("}", -1, PF_MODE_NORMAL);
  533.         return;
  534.  
  535.     case TTIME:
  536.         PrintIndentedString ("time\n", 1, PF_MODE_NORMAL);
  537.         PrintFunction (t->left, mode);
  538.         Print_indent--;
  539.         return;
  540.     }
  541. }
  542.  
  543.  
  544. /*
  545.  * Print a command line
  546.  */
  547.  
  548. static void F_LOCAL PrintCommand (register C_Op *t, int mode)
  549. {
  550.     IO_Actions    **iopp;
  551.     char    **wp;
  552.     int        i;
  553.  
  554. /* Parenthesis ? */
  555.  
  556.     if (t->type == TPAREN)
  557.     {
  558.     PrintIndentedString ("(\n", 1, PF_MODE_NORMAL);
  559.     PrintFunction (t->left, PF_MODE_NORMAL);
  560.     PrintIndentedString (")", -1, PF_MODE_NO);
  561.  
  562.     }
  563.  
  564.     else
  565.     {
  566.     PrintIndentedString (null, 0, PF_MODE_NORMAL);
  567.  
  568.  /* Process arguments and assigments */
  569.  
  570.     for (i = 0, wp = t->vars; i < 2; i++)
  571.     {
  572.         if (wp != NOWORDS)
  573.         {
  574.         while (*wp != NOWORD)
  575.         {
  576.             PrintVarArg ((unsigned char *)*(wp++));
  577.  
  578.             if (*wp != NOWORD)
  579.             fputchar (CHAR_SPACE);
  580.         }
  581.         }
  582.  
  583.         wp = t->args;
  584.     }
  585.     }
  586.  
  587. /* Set up anyother IO required */
  588.  
  589.     if ((iopp = t->ioact) != (IO_Actions **)NULL)
  590.     {
  591.     while (*iopp != (IO_Actions *)NULL)
  592.         PrintIOInformation (*(iopp++));
  593.     }
  594.  
  595.     PrintMode (mode);
  596. }
  597.  
  598. /*
  599.  * Print an argument or variable assigment string
  600.  */
  601.  
  602. static void F_LOCAL PrintVarArg (unsigned char *string)
  603. {
  604.     register unsigned     c;
  605.     register bool    quoted = FALSE;
  606.  
  607.     while (1)
  608.     {
  609.     switch ((c = *(string++)))
  610.     {
  611.         case WORD_EOS:    /* end of string            */
  612.         return;
  613.  
  614.         case WORD_CHAR:    /* unquoted character            */
  615.         fputMagicChar (*(string++));
  616.         break;
  617.  
  618.         case WORD_QCHAR:    /* quoted character            */
  619.         case WORD_QTCHAR:
  620.         if (!quoted)
  621.             fputchar (CHAR_META);
  622.  
  623.         fputMagicChar (*(string++));
  624.         break;
  625.  
  626.         case WORD_OQUOTE:    /* opening " or '            */
  627.         case WORD_ODQUOTE:
  628.         quoted = TRUE;
  629.         fputchar ((c == WORD_OQUOTE) ? CHAR_SINGLE_QUOTE
  630.                          : CHAR_DOUBLE_QUOTE);
  631.         break;
  632.  
  633.         case WORD_CQUOTE:    /* closing " or '            */
  634.         case WORD_CDQUOTE:
  635.         quoted = FALSE;
  636.         fputchar ((c == WORD_CQUOTE) ? CHAR_SINGLE_QUOTE
  637.                          : CHAR_DOUBLE_QUOTE);
  638.         break;
  639.  
  640.         case WORD_OARRAY:    /* Opening ${...[...] ...        */
  641.         fputchar (CHAR_OPEN_BRACKETS);
  642.         break;
  643.  
  644.         case WORD_CARRAY:    /* Closing ${...[...] ...        */
  645.         case WORD_OSUBST:    /* opening ${ substitution        */
  646.         if (c == WORD_CARRAY)
  647.             fputchar (CHAR_CLOSE_BRACKETS);
  648.  
  649. /* Start of variable - output the name */
  650.  
  651.         else
  652.         {
  653.             fputchar (CHAR_VARIABLE);
  654.             fputchar (CHAR_OPEN_BRACES);
  655.  
  656.             while ((c = *(string++)) != 0)
  657.             fputchar (c);
  658.         }
  659.  
  660. /* Check for some special characters */
  661.  
  662.         if ((*string != WORD_CSUBST) && (*string != WORD_OARRAY))
  663.         {
  664.             if (((c = *(string++)) & CHAR_MAGIC) &&
  665.             (IS_VarOp (c & 0x7f)))
  666.             {
  667.  
  668. /* Check for %% or ## */
  669.             if (((c &= 0x7f) == CHAR_MATCH_START) ||
  670.                 (c == CHAR_MATCH_END))
  671.                 fputMagicChar (c);
  672.  
  673. /* :?string case */
  674.             else
  675.                 fputMagicChar (':');
  676.  
  677.             }
  678.  
  679.             fputMagicChar (c);
  680.         }
  681.  
  682.         break;
  683.  
  684.         case WORD_CSUBST:    /* closing } of above            */
  685.         fputchar (CHAR_CLOSE_BRACES);
  686.         break;
  687.  
  688.         case WORD_COMSUB:    /* $() substitution (0 terminated)    */
  689.         case WORD_OMATHS:    /* opening $(()) substitution (0 term)    */
  690.         fputchar (CHAR_VARIABLE);
  691.         fputchar (CHAR_OPEN_PARATHENSIS);
  692.  
  693.         if (c == WORD_OMATHS)
  694.             fputchar (CHAR_OPEN_PARATHENSIS);
  695.  
  696.         while (*string != 0)
  697.             fputMagicChar (*(string++));
  698.  
  699.         string++;        /* Skip over the terminator    */
  700.         fputchar (CHAR_CLOSE_PARATHENSIS);
  701.  
  702.         if (c == WORD_OMATHS)
  703.             fputchar (CHAR_CLOSE_PARATHENSIS);
  704.  
  705.         break;
  706.     }
  707.     }
  708. }
  709.  
  710.  
  711. /*
  712.  * Output a potentially magic character
  713.  */
  714.  
  715. static void F_LOCAL fputMagicChar (unsigned int c)
  716. {
  717.     if ((c & 0x60) == 0)
  718.     {
  719.     fputchar ((c & CHAR_MAGIC) ? CHAR_VARIABLE : '^');
  720.     fputchar (((c & 0x7F) | 0x40));
  721.     }
  722.  
  723.     else if ((c&0x7F) == 0x7F)
  724.     {
  725.     fputchar ((c & CHAR_MAGIC) ? CHAR_VARIABLE : '^');
  726.     fputchar ('?');
  727.     }
  728.  
  729.     else
  730.     fputchar (c);
  731. }
  732.  
  733.  
  734. /*
  735.  * Print the IO re-direction
  736.  */
  737.  
  738. static void F_LOCAL PrintIOInformation (register IO_Actions *iop)
  739. {
  740.     int        unit = iop->io_unit;
  741.     int        IOflag = iop->io_flag & IOTYPE;
  742.     char    *type;
  743.     bool    TermQuote = FALSE;
  744.  
  745. /* Set up the IO type string and display it */
  746.  
  747.     type = IOTypes [IOflag - 1];
  748.  
  749.     if ((IOflag == IODUP) && (!unit))
  750.     type = "<&";
  751.  
  752.     printf (" %d%s", unit, type);
  753.  
  754. /* Print clobber override and skip tabs information on here documents */
  755.  
  756.     if (iop->io_flag & IOCLOBBER)
  757.     fputchar (CHAR_PIPE);
  758.  
  759.     if (iop->io_flag & IOSKIP)
  760.     fputchar (CHAR_HYPHEN);
  761.  
  762. /* Quoted here document ? */
  763.  
  764.     if ((TermQuote = C2bool ((IOflag == IOHERE) && (!(iop->io_flag & IOEVAL)))))
  765.     fputchar (CHAR_SINGLE_QUOTE);
  766.  
  767. /* Here document names are in expanded format */
  768.  
  769.     (IOflag == IOHERE) ? (void)foputs (iop->io_name)
  770.                : (void)PrintVarArg ((unsigned char *)iop->io_name);
  771.  
  772.     if (TermQuote)
  773.     fputchar (CHAR_SINGLE_QUOTE);
  774. }
  775.  
  776. /*
  777.  * Print out the contents of a case statement
  778.  */
  779.  
  780. static void F_LOCAL PrintCaseCommand (C_Op *t)
  781. {
  782.     register char    **wp;
  783.  
  784.     while (t != (C_Op *)NULL)
  785.     {
  786.  
  787. /* Print patterns (the conditions) */
  788.  
  789.     PrintIndentedString (null, 0, PF_MODE_NORMAL);
  790.  
  791.     for (wp = t->vars; *wp != NOWORD; )
  792.     {
  793.         PrintVarArg ((unsigned char *)*(wp++));
  794.  
  795.         if (*wp != NOWORD)
  796.         foputs (" | ");
  797.     }
  798.  
  799.     puts (" )");
  800.     Print_indent += 1;
  801.  
  802. /* print the functions */
  803.  
  804.     PrintFunction (t->left, PF_MODE_NORMAL);
  805.     PrintIndentedString (";;", -1, PF_MODE_NORMAL);
  806.     t = t->right;
  807.     }
  808. }
  809.  
  810. /*
  811.  * Print an indented string
  812.  */
  813.  
  814. static void F_LOCAL PrintIndentedString (char *cp, int indent, int mode)
  815. {
  816.     int        i;
  817.  
  818.     if (indent < 0)
  819.     Print_indent += indent;
  820.  
  821.     for (i = 0; i < (Print_indent / 2); i++)
  822.     fputchar (CHAR_TAB);
  823.  
  824.     if (Print_indent % 2)
  825.     foputs ("    ");
  826.  
  827.     foputs (cp);
  828.  
  829. /* Append the mode */
  830.  
  831.     if ((mode != PF_MODE_NORMAL) || (indent < 0))
  832.     PrintMode (mode);
  833.  
  834.     if (indent > 0)
  835.     Print_indent += indent;
  836. }
  837.  
  838. /*
  839.  * Output mode
  840.  */
  841.  
  842. static void F_LOCAL PrintMode (int mode)
  843. {
  844.     if (mode == PF_MODE_ASYNC)
  845.     foputs (" &\n");
  846.     
  847.     else if (mode == PF_MODE_COPROC)
  848.     foputs (" |&\n");
  849.  
  850.     else if (mode == PF_MODE_NORMAL)
  851.     fputchar (CHAR_NEW_LINE);
  852. }
  853.     
  854. /*
  855.  * TWALK and TDELETE compare functions for FUNCTION, ALIAS and JOB trees
  856.  *
  857.  * Note: We know about these two function, so we know the key is always
  858.  *       the first parameter.  So we only pass the char * not the FunctionList
  859.  *       pointer (in the case of JOB, its an int *)
  860.  */
  861.  
  862. static int FindFunction (const void *key1, const void *key2)
  863. {
  864.     return strcmp (key1, ((FunctionList *)key2)->tree->str);
  865. }
  866.  
  867. static int FindAlias (const void *key1, const void *key2)
  868. {
  869.     return strcmp (key1, ((AliasList *)key2)->name);
  870. }
  871.  
  872. /* By string name */
  873.  
  874. #if (OS_TYPE != OS_DOS)
  875. static void FindJobByString (const void *key, VISIT visit, int level)
  876. {
  877.     if (JobSearchEntry != (JobList **)NULL)
  878.     return;
  879.  
  880.     if (((visit == postorder) || (visit == leaf)) &&
  881.     (((*JobSearchKey == CHAR_MATCH_ANY) &&
  882.       (strstr (((JobList *)key)->Command, JobSearchKey) != (char *)NULL)) ||
  883.      ((*JobSearchKey != CHAR_MATCH_ANY) &&
  884.       (strncmp (JobSearchKey, ((JobList *)key)->Command,
  885.            strlen (JobSearchKey)) == 0))))
  886.     JobSearchEntry = (JobList **)&key;
  887. }
  888.  
  889. /* By process id */
  890.  
  891. static int FindJobByPID (const void *key1, const void *key2)
  892. {
  893.     return *(PID *)key1 - ((JobList *)key2)->pid;
  894. }
  895.  
  896. /* By session id */
  897.  
  898. static int FindJobBySession (const void *key1, const void *key2)
  899. {
  900.     return *(unsigned short *)key1 - ((JobList *)key2)->SessionId;
  901. }
  902.  
  903. /* By job number */
  904.  
  905. static int FindJob (const void *key1, const void *key2)
  906. {
  907.     return *(int *)key1 - ((JobList *)key2)->Number;
  908. }
  909. #endif
  910.  
  911. /*
  912.  * Look up a function in the save tree
  913.  */
  914.  
  915. FunctionList *LookUpFunction (char *name, bool AllowDot)
  916. {
  917.     FunctionList    **fp = (FunctionList **)NULL;
  918.     
  919.     if (AllowDot || (*name != '.'))
  920.     fp = (FunctionList **)tfind (name, &FunctionTree, FindFunction);
  921.  
  922.     return fp != (FunctionList **)NULL ? *fp : (FunctionList *)NULL;
  923. }
  924.  
  925.  
  926. /*
  927.  * TSEARCH compare functions for FUNCTION, ALIAS and JOB trees
  928.  */
  929.  
  930. static int SearchFunction (const void *key1, const void *key2)
  931. {
  932.     return strcmp (((FunctionList *)key1)->tree->str,
  933.            ((FunctionList *)key2)->tree->str);
  934. }
  935.  
  936. static int SearchAlias (const void *key1, const void *key2)
  937. {
  938.     return strcmp (((AliasList *)key1)->name, ((AliasList *)key2)->name);
  939. }
  940.  
  941. #if (OS_TYPE != OS_DOS)
  942. static int SearchJob (const void *key1, const void *key2)
  943. {
  944.     return ((JobList *)key1)->Number - ((JobList *)key2)->Number;
  945. }
  946. #endif
  947.  
  948. /*
  949.  * SAVE/DELETE A FUNCTION
  950.  */
  951.  
  952. /*
  953.  * Save a function tree
  954.  */
  955.  
  956. bool SaveFunction (C_Op *t)
  957. {
  958.     char            *name = t->str;
  959.     register FunctionList    *fp;
  960.     void            (*save_signal)(int);
  961.     char            *sname = name;
  962.  
  963. /* Allow dot as the first character */
  964.  
  965.     if ((*name == '.') && (strlen (name) > (size_t)1))
  966.     sname++;
  967.  
  968.     if (!IsValidAliasName (sname, FALSE))
  969.     {
  970.     PrintWarningMessage (BasicErrorMessage, name, LIT_Invalidfunction);
  971.     return FALSE;
  972.     }
  973.  
  974. /* Create new entry */
  975.  
  976.     if ((fp = (FunctionList *)GetAllocatedSpace (sizeof (FunctionList)))
  977.     == (FunctionList *)NULL)
  978.     return FALSE;
  979.  
  980. /* Delete the old function if it exists */
  981.  
  982.     DeleteFunction (t);
  983.  
  984. /* Disable signals */
  985.  
  986.     save_signal = signal (SIGINT, SIG_IGN);
  987.     fp->tree = t;
  988.     fp->Traced = FALSE;
  989.  
  990. /* Set up the tree */
  991.  
  992.     if (tsearch (fp, &FunctionTree, SearchFunction) != (void *)NULL)
  993.     {
  994.     SetMemoryAreaNumber ((void *)fp, 0);
  995.     SaveReleaseExecuteTree (t, SaveTreeEntry);
  996.     }
  997.  
  998. /* Restore signals */
  999.  
  1000.     signal (SIGINT, save_signal);
  1001.     return TRUE;
  1002. }
  1003.  
  1004. /*
  1005.  * Clean up functions on exit.  We should just delete the files, but its
  1006.  * easier to delete the functions
  1007.  */
  1008.  
  1009. void DeleteAllFunctions (void)
  1010. {
  1011.     void            (*save_signal)(int);
  1012.  
  1013.     save_signal = signal (SIGINT, SIG_IGN);
  1014.     twalk (FunctionTree, DeleteAFunction);
  1015.     signal (SIGINT, save_signal);
  1016. }
  1017.  
  1018. /*
  1019.  * Associate TREE WALK function to delete all functions
  1020.  */
  1021.  
  1022. static void DeleteAFunction (const void *key, VISIT visit, int level)
  1023. {
  1024.     if ((visit == postorder) || (visit == leaf))
  1025.     SaveReleaseExecuteTree ((*(FunctionList **)key)->tree,
  1026.                     ReleaseMemoryCell);
  1027. }
  1028.  
  1029. /*
  1030.  * Delete a function tree
  1031.  */
  1032.  
  1033. void DeleteFunction (C_Op *t)
  1034. {
  1035.     char            *name = t->str;
  1036.     register FunctionList    *fp = LookUpFunction (name, TRUE);
  1037.     void            (*save_signal)(int);
  1038.  
  1039.     if (fp == (FunctionList *)NULL)
  1040.     return;
  1041.  
  1042. /* Disable signals */
  1043.  
  1044.     save_signal = signal (SIGINT, SIG_IGN);
  1045.  
  1046. /* Free the tree and delete the entry */
  1047.  
  1048.     tdelete (name, &FunctionTree, FindFunction);
  1049.     SaveReleaseExecuteTree (fp->tree, ReleaseMemoryCell);
  1050.     ReleaseMemoryCell ((void *)fp);
  1051.  
  1052. /* Restore signals */
  1053.  
  1054.     signal (SIGINT, save_signal);
  1055. }
  1056.  
  1057.  
  1058. /*
  1059.  * Set ExTree areas to zero function
  1060.  */
  1061.  
  1062. static void  SaveTreeEntry (void *s)
  1063. {
  1064.     SetMemoryAreaNumber (s, 0);
  1065. }
  1066.  
  1067. /*
  1068.  * Set/Free function tree area by recursively processing of tree
  1069.  */
  1070.  
  1071. static void F_LOCAL SaveReleaseExecuteTree (C_Op *t, void (* func)(void *))
  1072. {
  1073.     if (t == (C_Op *)NULL)
  1074.     return;
  1075.  
  1076. /*
  1077.  * Process the tree - saving or deleting
  1078.  */
  1079.  
  1080.     if (t->str != (char *)NULL)
  1081.     (*func)((void *)t->str);
  1082.  
  1083.     SaveReleaseWordList (t->vars, func);
  1084.     SaveReleaseWordList (t->args, func);
  1085.     SaveReleaseIOActions (t->ioact, func);
  1086.     SaveReleaseExecuteTree (t->left, func);
  1087.     SaveReleaseExecuteTree (t->right, func);
  1088.  
  1089.     (*func)((void *)t);
  1090. }
  1091.  
  1092.  
  1093. /*
  1094.  * Save/Release a Block of words
  1095.  */
  1096.  
  1097. static void F_LOCAL SaveReleaseWordList (char **list, void (* func)(void *))
  1098. {
  1099.     char    **Slist = list;
  1100.  
  1101.     if (list == NOWORDS)
  1102.         return;
  1103.  
  1104. /* Ok - save/release it */
  1105.  
  1106.     while (*list != NOWORD)
  1107.     (*func)((void *)*(list++));
  1108.  
  1109. /* Handle the block itself */
  1110.  
  1111.     (*func)((void *)Slist);
  1112. }
  1113.  
  1114.  
  1115. /*
  1116.  * Save/Release the IO Actions block
  1117.  */
  1118.  
  1119. static void F_LOCAL SaveReleaseIOActions (IO_Actions **list, void (* func)(void *))
  1120. {
  1121.     IO_Actions    **Slist = list;
  1122.  
  1123.     if (list == (IO_Actions **)NULL)
  1124.         return;
  1125.  
  1126. /* Ok - save/release it */
  1127.  
  1128.     while (*list != (IO_Actions *)NULL)
  1129.     {
  1130.  
  1131. /*
  1132.  * If this is a Here Document, we need some clever processing to stop it
  1133.  * beening deleted or to delete it when the function disappears
  1134.  */
  1135.  
  1136.     if (((*list)->io_flag & IOTYPE) == IOHERE)
  1137.     {
  1138.  
  1139. /*
  1140.  * Mark this is a function file name.  This should stop the here processing
  1141.  * from deleting it
  1142.  */
  1143.  
  1144.         (*list)->io_flag |= IOFUNCTION;
  1145.  
  1146. /* If this is a delete - delete the file name */
  1147.  
  1148.         if (func == ReleaseMemoryCell)
  1149.         unlink ((*list)->io_name);
  1150.     }
  1151.  
  1152. /* OK, normal processing now!! */
  1153.  
  1154.     (*func)((void *)(*list)->io_name);
  1155.     (*func)((void *)*(list++));
  1156.     }
  1157.  
  1158. /* Handle the block itself */
  1159.  
  1160.     (*func)((void *)Slist);
  1161. }
  1162.  
  1163.  
  1164. /*
  1165.  * FUNCTION TREE DUPLICATION
  1166.  */
  1167.  
  1168. /*
  1169.  * Copy function tree area by recursively processing of tree
  1170.  */
  1171.  
  1172. static C_Op * F_LOCAL DuplicateFunctionTree (C_Op *Old_t)
  1173. {
  1174.     C_Op    *New_t;
  1175.  
  1176.     if (Old_t == (C_Op *)NULL)
  1177.     return (C_Op *)NULL;
  1178.  
  1179. /*
  1180.  * This will copy function and for identifiers quite accidently
  1181.  */
  1182.  
  1183.     New_t        = (C_Op *)DuplicateMemoryCell (Old_t);
  1184.     New_t->str   = DuplicateMemoryArea (Old_t->str, char *);
  1185.     New_t->vars  = DuplicateWordList (Old_t->vars);
  1186.     New_t->args  = DuplicateWordList (Old_t->args);
  1187.     New_t->ioact = DuplicateIOActions (Old_t->ioact);
  1188.     New_t->left  = DuplicateFunctionTree (Old_t->left);
  1189.     New_t->right = DuplicateFunctionTree (Old_t->right);
  1190.     return New_t;
  1191. }
  1192.  
  1193.  
  1194. /*
  1195.  * Duplicate a Block of words
  1196.  */
  1197.  
  1198. static char ** F_LOCAL DuplicateWordList (char **list)
  1199. {
  1200.     char    **Nlist;
  1201.     char    **Np;
  1202.  
  1203.     if ((Nlist = DuplicateMemoryArea (list, char **)) == (char **)NULL)
  1204.         return NOWORDS;
  1205.  
  1206. /* Ok - dup it */
  1207.  
  1208.     for (Np = Nlist; *list != NOWORD; list++)
  1209.     *(Np++) = DuplicateMemoryArea (*list, char *);
  1210.  
  1211. /* Terminate it */
  1212.  
  1213.     *Np = NOWORD;
  1214.  
  1215.     return Nlist;
  1216. }
  1217.  
  1218.  
  1219. /*
  1220.  * Duplicate the IO Actions block
  1221.  */
  1222.  
  1223. static IO_Actions ** F_LOCAL DuplicateIOActions (IO_Actions **list)
  1224. {
  1225.     IO_Actions    **Nlist;
  1226.     IO_Actions    **Np;
  1227.  
  1228.     if ((Nlist = DuplicateMemoryArea (list,
  1229.                       IO_Actions **)) == (IO_Actions **)NULL)
  1230.         return (IO_Actions **)NULL;
  1231.  
  1232. /* Ok - dup it */
  1233.  
  1234.     for (Np = Nlist; *list != (IO_Actions *)NULL; list++, Np++)
  1235.     {
  1236.     *Np = (IO_Actions *)DuplicateMemoryCell (*list);
  1237.     (*Np)->io_name = DuplicateMemoryArea ((*list)->io_name, char *);
  1238.     }
  1239.  
  1240. /* Terminate it */
  1241.  
  1242.     *Np = (IO_Actions *)NULL;
  1243.     return Nlist;
  1244. }
  1245.  
  1246.  
  1247. /*
  1248.  * Duplicate the tree
  1249.  */
  1250.  
  1251. C_Op        *CopyFunction (C_Op *Old_t)
  1252. {
  1253.     ErrorPoint    save_ErrorReturnPoint;
  1254.     jmp_buf    new_ErrorReturnPoint;
  1255.     C_Op    *New_t = (C_Op *)NULL;
  1256.  
  1257. /* Set up for error handling - like out of space */
  1258.  
  1259.     save_ErrorReturnPoint = e.ErrorReturnPoint;
  1260.  
  1261.     if (SetErrorPoint (new_ErrorReturnPoint) == 0)
  1262.     New_t = DuplicateFunctionTree (Old_t);
  1263.  
  1264.     e.ErrorReturnPoint = save_ErrorReturnPoint;
  1265.     return New_t;
  1266. }
  1267.  
  1268. /*
  1269.  * Alias processing
  1270.  */
  1271.  
  1272. void PrintAlias (char *name)
  1273. {
  1274.     register AliasList    *al = LookUpAlias (name, FALSE);
  1275.  
  1276.     if ((al == (AliasList *)NULL) || (al->value == null))
  1277.     return;
  1278.  
  1279.     printf (ListVarFormat, name, al->value);
  1280. }
  1281.  
  1282. /*
  1283.  * Print All Aliases
  1284.  */
  1285.  
  1286. int  PrintAllAlias (bool tracked)
  1287. {
  1288.     DisplayListMode = tracked;        /* Set mode            */
  1289.  
  1290.     twalk (AliasTree, DisplayAlias);
  1291.     return 0;
  1292. }
  1293.  
  1294. /*
  1295.  * Save an alias
  1296.  */
  1297.  
  1298. bool SaveAlias (char *name, char *arguments, bool tracked)
  1299. {
  1300.     register AliasList    *al;
  1301.     void        (*save_signal)(int);
  1302.  
  1303.  
  1304. /* Create new entry */
  1305.  
  1306.     if (((al = (AliasList *)GetAllocatedSpace (sizeof (AliasList)))
  1307.         == (AliasList *)NULL) ||
  1308.     ((al->name = GetAllocatedSpace (strlen (name) + 1)) == (char *)NULL))
  1309.     return FALSE;
  1310.  
  1311.     if ((arguments != null) &&
  1312.     ((al->value = GetAllocatedSpace (strlen (arguments) + 1))
  1313.         == (char *)NULL))
  1314.     return FALSE;
  1315.  
  1316. /* Delete old name */
  1317.  
  1318.     DeleteAlias (name);
  1319.  
  1320. /* Disable signals */
  1321.  
  1322.     save_signal = signal (SIGINT, SIG_IGN);
  1323.     strcpy (al->name, name);
  1324.  
  1325. /* Add it to the tree */
  1326.  
  1327.     if (tsearch (al, &AliasTree, SearchAlias) != (void *)NULL)
  1328.     {
  1329.     SetMemoryAreaNumber ((void *)al, 0);
  1330.     SetMemoryAreaNumber ((void *)al->name, 0);
  1331.  
  1332.     if (arguments != null)
  1333.         SetMemoryAreaNumber ((void *)strcpy (al->value, arguments), 0);
  1334.  
  1335.     else
  1336.         al->value = null;
  1337.  
  1338.         if (tracked)
  1339.         al->AFlags = ALIAS_TRACKED;
  1340.     }
  1341.  
  1342.  
  1343. /* Restore signals */
  1344.  
  1345.     signal (SIGINT, save_signal);
  1346.     return TRUE;
  1347. }
  1348.  
  1349. /*
  1350.  * Delete an alias
  1351.  */
  1352.  
  1353. void DeleteAlias (char *name)
  1354. {
  1355.     register AliasList    **alp = (AliasList **)tfind (name, &AliasTree,
  1356.                              FindAlias);
  1357.     void        (*save_signal)(int);
  1358.     register AliasList    *al;
  1359.  
  1360.     if (alp == (AliasList **)NULL)
  1361.     return;
  1362.  
  1363. /* Disable signals */
  1364.  
  1365.     save_signal = signal (SIGINT, SIG_IGN);
  1366.  
  1367. /* Delete the tree entry and release the memory */
  1368.  
  1369.     al = *alp;
  1370.     tdelete (name, &AliasTree, FindAlias);
  1371.     ReleaseMemoryCell ((void *)al->name);
  1372.  
  1373.     if (al->value != null)
  1374.     ReleaseMemoryCell ((void *)al->value);
  1375.  
  1376.     ReleaseMemoryCell ((void *)al);
  1377.  
  1378. /* Restore signals */
  1379.  
  1380.     signal (SIGINT, save_signal);
  1381. }
  1382.  
  1383. /*
  1384.  * Search for an Alias
  1385.  */
  1386.  
  1387. AliasList    *LookUpAlias (char *name, bool CreateTracked)
  1388. {
  1389.     AliasList    **alp = (AliasList **)tfind (name, &AliasTree, FindAlias);
  1390.     char    *path;
  1391.  
  1392. /* If we found a tracked alias, which has been untracked, re-track it if
  1393.  * necesary
  1394.  */
  1395.  
  1396.     if ((alp != (AliasList **)NULL) && ((*alp)->value == null))
  1397.     {
  1398.         if (CreateTracked &&
  1399.         ((path = AllocateMemoryCell (FFNAME_MAX)) != (char *)NULL) &&
  1400.         (FindLocationOfExecutable (path, name) != EXTENSION_NOT_FOUND))
  1401.         {
  1402.         SetMemoryAreaNumber ((void *)path, 0);
  1403.         (*alp)->value = PATH_TO_UNIX (path);
  1404.         return *alp;
  1405.         }
  1406.  
  1407.         else
  1408.             return (AliasList *)NULL;
  1409.     }
  1410.  
  1411.     return (alp == (AliasList **)NULL) ? (AliasList *)NULL : *alp;
  1412. }
  1413.  
  1414. /*
  1415.  * Check for valid alias name
  1416.  */
  1417.  
  1418. bool IsValidAliasName (char *s, bool alias)
  1419. {
  1420.     if (!IS_VariableFC ((int)*s) || LookUpSymbol (s))
  1421.     return FALSE;
  1422.  
  1423.     while (IS_VariableSC ((int)*s))
  1424.         ++s;
  1425.  
  1426.     return C2bool (!*s);
  1427. }
  1428.  
  1429. /*
  1430.  * Untrack all Aliases
  1431.  */
  1432.  
  1433. void UnTrackAllAliases (void)
  1434. {
  1435.     twalk (AliasTree, UntrackAlias);
  1436. }
  1437.  
  1438. /*
  1439.  * The associate TWALK function
  1440.  */
  1441.  
  1442. static void  UntrackAlias (const void *key, VISIT visit, int level)
  1443. {
  1444.     AliasList    *al = *(AliasList **)key;
  1445.  
  1446.     if (((visit == postorder) || (visit == leaf)) &&
  1447.     (al->AFlags & ALIAS_TRACKED) && (al->value != null))
  1448.     {
  1449.      ReleaseMemoryCell ((void *)al->value);
  1450.      al->value = null;
  1451.     }
  1452. }
  1453.  
  1454. /*
  1455.  * Look up a job in the save tree
  1456.  */
  1457.  
  1458. #if (OS_TYPE != OS_DOS)
  1459. JobList *LookUpJob (int JobNumber)
  1460. {
  1461.     JobList    **jp = (JobList **)tfind (&JobNumber, &JobTree, FindJob);
  1462.  
  1463.     return jp != (JobList **)NULL ? *jp : (JobList *)NULL;
  1464. }
  1465.  
  1466. /*
  1467.  * Search for a job
  1468.  */
  1469.  
  1470. JobList    *SearchForJob (char *String)
  1471. {
  1472.     JobSearchKey = String;
  1473.     JobSearchEntry = (JobList **)NULL;
  1474.  
  1475.     if ((strcmp (String, "%") == 0) || (strcmp (String, "+") == 0))
  1476.     return LookUpJob (CurrentJob);
  1477.  
  1478.     else if (strcmp (String, "-") == 0)
  1479.     return LookUpJob (PreviousJob);
  1480.  
  1481. /* Search for it */
  1482.  
  1483.     twalk (JobTree, FindJobByString);
  1484.     return JobSearchEntry != (JobList **)NULL ? *JobSearchEntry
  1485.                           : (JobList *)NULL;
  1486. }
  1487.  
  1488. /*
  1489.  * Delete a job by Session ID
  1490.  */
  1491.  
  1492. void    DeleteJobBySession (unsigned short SessionId)
  1493. {
  1494.     register JobList    **jpp = (JobList **)tfind (&SessionId, &JobTree,
  1495.                            FindJobBySession);
  1496.  
  1497.     if (jpp != (JobList **)NULL)
  1498.     DeleteJob ((*jpp)->pid);
  1499. }
  1500.  
  1501. /*
  1502.  * Delete a job by Process ID
  1503.  */
  1504.  
  1505. void DeleteJob (PID pid)
  1506. {
  1507.     register JobList    **jpp = (JobList **)tfind (&pid, &JobTree,
  1508.                            FindJobByPID);
  1509.     void        (*save_signal)(int);
  1510.     JobList        *jp;
  1511.  
  1512.     if (jpp == (JobList **)NULL)
  1513.     return;
  1514.  
  1515. /* Disable signals */
  1516.  
  1517.     save_signal = signal (SIGINT, SIG_IGN);
  1518.     jp = *jpp;
  1519.  
  1520. /* Free the tree and delete the entry */
  1521.  
  1522.     tdelete (&pid, &JobTree, FindJobByPID);
  1523.  
  1524.     if (jp->Number == PreviousJob)
  1525.     PreviousJob = 0;
  1526.  
  1527.     if (jp->Number == CurrentJob)
  1528.     CurrentJob = PreviousJob;
  1529.  
  1530.     ReleaseMemoryCell ((void *)jp->Command);
  1531.     ReleaseMemoryCell ((void *)jp);
  1532.  
  1533. /* Restore signals */
  1534.  
  1535.     signal (SIGINT, save_signal);
  1536. }
  1537.  
  1538. /*
  1539.  * Save a job ID
  1540.  */
  1541.  
  1542. int    AddNewJob (PID pid, unsigned short SessionId, char *command)
  1543. {
  1544.     register JobList    *jp;
  1545.     static int        JobNumber = 1;
  1546.     void        (*save_signal)(int);
  1547.     char        *tmp;
  1548.  
  1549. /* We if we can get the full command */
  1550.  
  1551.    if ((tmp = GetLastHistoryString ()) != (char *)NULL)
  1552.        command = tmp;
  1553.  
  1554. /* Create new entry */
  1555.  
  1556.     if (((jp = (JobList *)GetAllocatedSpace (sizeof (JobList))) == (JobList *)NULL) ||
  1557.     ((jp->Command = GetAllocatedSpace (strlen (command) + 1)) == (char *)NULL))
  1558.     return 0;
  1559.  
  1560. /* Get the next available job number */
  1561.  
  1562.     while (TRUE)
  1563.     {
  1564.     jp->pid = pid;
  1565.     jp->Number = JobNumber++;
  1566.     jp->SessionId = SessionId;
  1567.  
  1568.     if (JobNumber > 32000)
  1569.         JobNumber = 1;
  1570.  
  1571.     if (tfind (jp, &JobTree, SearchJob) == (void *)NULL)
  1572.         break;
  1573.     }
  1574.  
  1575. /* Disable signals */
  1576.  
  1577.     save_signal = signal (SIGINT, SIG_IGN);
  1578.  
  1579.     if (tsearch (jp, &JobTree, SearchJob) != (void *)NULL)
  1580.     {
  1581.     SetMemoryAreaNumber ((void *)jp, 0);
  1582.     SetMemoryAreaNumber ((void *)strcpy (jp->Command, command), 0);
  1583.     PATH_TO_UNIX (jp->Command);
  1584.     }
  1585.  
  1586. /* Restore signals */
  1587.  
  1588.     signal (SIGINT, save_signal);
  1589.  
  1590.     PreviousJob = CurrentJob;
  1591.     return CurrentJob = jp->Number;
  1592. }
  1593.  
  1594. /*
  1595.  * Display Jobs
  1596.  */
  1597.  
  1598. int PrintJobs (bool Mode)
  1599. {
  1600.     DisplayListMode = Mode;        /* Set mode            */
  1601.  
  1602.     twalk (JobTree, DisplayJob);
  1603.     return 0;
  1604. }
  1605.  
  1606. /*
  1607.  * Count the number of active jobs
  1608.  */
  1609.  
  1610. int NumberOfActiveJobs (void)
  1611. {
  1612.     NumberOfJobs = 0;
  1613.  
  1614.     twalk (JobTree, CountJob);
  1615.     return NumberOfJobs;
  1616. }
  1617. #endif
  1618.  
  1619. /*
  1620.  * OS2 1.x - Parse the kernel process information
  1621.  */
  1622.  
  1623. #if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_16)
  1624. static bool F_LOCAL Parse_V1ProcessTable (UCHAR * bBuf, V1ProcessStatus_t *pi)
  1625. {
  1626.     USHORT    sel, offs;
  1627.     USHORT    type, tpid;
  1628.     USHORT    count, kount;
  1629.     UCHAR    buffer[256];
  1630.     UCHAR    *cptr, *ptr;
  1631.  
  1632.     ptr = bBuf;
  1633.     sel = SELECTOROF (ptr);
  1634.  
  1635.     while ((type = *(USHORT *) ptr) != 0xFFFFU )
  1636.     {
  1637.     ptr += 2;
  1638.     offs = *(USHORT *) ptr;
  1639.     ptr += 2;
  1640.  
  1641.     switch ( type )
  1642.     {
  1643.         case 0:                    /* Process */
  1644.         if (pi->N_Processes >= pi->M_Processes)
  1645.         {
  1646.             V1Process_t    **newp = (V1Process_t **)ReAllocateSpace (
  1647.                             (void *)pi->V1Processes,
  1648.                                (pi->M_Processes + 50) *
  1649.                             sizeof (V1Process_t *));
  1650.  
  1651.             if (newp == (V1Process_t **)NULL)
  1652.             return TRUE;
  1653.  
  1654.             pi->V1Processes = newp;
  1655.             pi->M_Processes += 50;
  1656.         }
  1657.  
  1658. /* Create the process entry */
  1659.  
  1660.         pi->V1Processes[pi->N_Processes] =
  1661.             (V1Process_t *) GetAllocatedSpace (sizeof (V1Process_t));
  1662.  
  1663.         if (pi->V1Processes[pi->N_Processes] == (V1Process_t *)NULL)
  1664.             return TRUE;
  1665.  
  1666.         pi->V1Processes[pi->N_Processes]->pid = *(USHORT *)ptr;
  1667.         ptr += 2;
  1668.         pi->V1Processes[pi->N_Processes]->ppid = *(USHORT *) ptr;
  1669.         ptr += 2;
  1670.         ptr += 2;
  1671.         pi->V1Processes[pi->N_Processes]->modhandle = *(USHORT *) ptr;
  1672.         pi->V1Processes[pi->N_Processes++]->threads = 0;
  1673.  
  1674.         break;
  1675.  
  1676.         case 1:                 /* Thread     */
  1677.         ptr += 2;
  1678.         tpid = *(USHORT *) ptr;
  1679.  
  1680. /* Increment the thread count for the process */
  1681.  
  1682.         for (count = 0; count < pi->N_Processes; count++)
  1683.         {
  1684.             if (pi->V1Processes[count]->pid == tpid)
  1685.             {
  1686.             ++pi->V1Processes[count]->threads;
  1687.             break;
  1688.             }
  1689.         }
  1690.  
  1691.         break;
  1692.  
  1693.         case 2:                    /* module    */
  1694.         if (pi->N_Modules >= pi->M_Modules)
  1695.         {
  1696.             V1Module_t    **newm = (V1Module_t **)ReAllocateSpace (
  1697.                             (void *)pi->V1Modules,
  1698.                         (pi->M_Modules + 50) *
  1699.                             sizeof (V1Module_t *));
  1700.  
  1701.             if (newm == (V1Module_t **)NULL)
  1702.             return TRUE;
  1703.  
  1704.             pi->V1Modules = newm;
  1705.             pi->M_Modules += 50;
  1706.         }
  1707.  
  1708.         pi->V1Modules[pi->N_Modules]
  1709.             = (V1Module_t *)GetAllocatedSpace (sizeof(V1Module_t));
  1710.  
  1711.         if (pi->V1Modules[pi->N_Modules] == (V1Module_t *)NULL)
  1712.             return TRUE;
  1713.  
  1714.         pi->V1Modules[pi->N_Modules]->modhandle = *(USHORT *) ptr;
  1715.         ptr += 2;
  1716.         pi->V1Modules[pi->N_Modules]->max_dependents = *(USHORT *) ptr;
  1717.         ptr += 2;
  1718.         ptr += 2;
  1719.         ptr += 2;
  1720.  
  1721.         if (pi->V1Modules[pi->N_Modules] -> max_dependents)
  1722.             ptr += (pi->V1Modules[pi->N_Modules] -> max_dependents) * 2;
  1723.  
  1724.         for (cptr = buffer; *cptr++ = *ptr++;)
  1725.             continue;
  1726.  
  1727.         if ((pi->V1Modules[pi->N_Modules]->modname =
  1728.             StringCopy (buffer)) == null)
  1729.             return 1;
  1730.  
  1731.         ++pi->N_Modules;
  1732.  
  1733.         break;
  1734.  
  1735.         case 3:                /* system semaphore    */
  1736.         case 4:                /* shared memory    */
  1737.         break;
  1738.     }
  1739.  
  1740.     ptr = MAKEP(sel, offs);
  1741.     }
  1742.  
  1743. /* Count modules */
  1744.  
  1745.     for (count = 0; count < pi->N_Processes; count++)
  1746.     {
  1747.     for (kount = 0; kount < pi->N_Modules; kount++)
  1748.     {
  1749.         if (pi->V1Processes[count]->modhandle ==
  1750.         pi->V1Modules[kount]->modhandle)
  1751.         {
  1752.         pi->V1Processes[count]->module = kount;
  1753.         break;
  1754.         }
  1755.     }
  1756.     }
  1757.  
  1758. /* Count children */
  1759.  
  1760.     for (count = 0; count < pi->N_Processes; count++)
  1761.     {
  1762.     for (kount = 0; kount < pi->N_Processes; kount++)
  1763.     {
  1764.         if (pi->V1Processes[count]->pid == pi->V1Processes[kount]->ppid)
  1765.         (pi->V1Processes[count]->children)++;
  1766.     }
  1767.     }
  1768.  
  1769.     return FALSE;
  1770. }
  1771.  
  1772. /*
  1773.  * Process the process information
  1774.  */
  1775.  
  1776. static void F_LOCAL PrintV1ProcessTree (pid_t pid, int indent,
  1777.                     V1ProcessStatus_t *pi)
  1778. {
  1779.     USHORT    count;
  1780.     UCHAR    *mName, pName[256];
  1781.  
  1782.     for (count = 0; count < pi->N_Processes; count++)
  1783.     {
  1784.     if ((indent &&    (pi->V1Processes[count]->ppid == (USHORT)pid)) ||
  1785.         ((!indent) && (pi->V1Processes[count]->pid == (USHORT)pid)))
  1786.     {
  1787.         if (pi->V1Processes[count]->module)
  1788.         {
  1789.         mName = pi->V1Modules[pi->V1Processes[count]->module]->modname;
  1790.         DosGetModName (pi->V1Processes[count]->modhandle,
  1791.                    sizeof(pName), pName);
  1792.         }
  1793.  
  1794.         else
  1795.         {
  1796.         mName = "unknown";  /* Zombie process,    */
  1797.         pName[0] = 0;
  1798.         }
  1799.  
  1800.         printf ("%5d %5d %3d %-8s %*s%s\n", pi->V1Processes[count]->pid,
  1801.             pi->V1Processes[count]->ppid,
  1802.             pi->V1Processes[count]->threads, mName, indent, "", pName);
  1803.  
  1804.         PrintV1ProcessTree (pi->V1Processes[count]->pid, indent + 2, pi);
  1805.     }
  1806.     }
  1807. }
  1808.  
  1809.  
  1810. static int SortV1Processes (void *p1, void *p2)
  1811. {
  1812.     return (*(V1Process_t **)p1)->pid - (*(V1Process_t **)p2)->pid;
  1813. }
  1814. #endif
  1815.  
  1816. /*
  1817.  * OS/2 2.x 32-bit version - Display Process Tree
  1818.  */
  1819.  
  1820. #if (OS_TYPE == OS_OS2)
  1821. static void F_LOCAL V2_DisplayProcessTree (USHORT pid, USHORT indent,
  1822.                        V2ProcessStatus_t *ps)
  1823. {
  1824.     V2Process_t        *proc;
  1825.     UCHAR        name[FFNAME_MAX];
  1826.     USHORT        prty;
  1827.  
  1828. /* Not sure if there isn't another termination method    */
  1829.  
  1830.     for (proc = PTR (ps->ppi); (proc->ulEndIndicator != PROCESS_END_INDICATOR);
  1831.          proc = (V2Process_t *) PTR (proc->ptiFirst + proc->usThreadCount))
  1832.     {
  1833.     if ((indent    && (proc->pidParent == pid)) ||
  1834.         ((!indent) && (proc->pid == pid)))
  1835.     {
  1836. #  if (OS_SIZE == OS_32)
  1837.         if (DosQueryModuleName (proc->hModRef, sizeof (name), name))
  1838. #  else
  1839.         if (DosGetModName (proc->hModRef, sizeof (name), name))
  1840. #  endif
  1841.         strcpy(name, "<unknown>");
  1842.  
  1843.         if (Dos32GetPrty (PRTYS_PROCESS, &prty, proc->pid))
  1844.         prty = 0;
  1845.  
  1846.         printf ("%5d %5d %3d %04x %*s%s\n", proc->pid, proc->pidParent,
  1847.                 proc->usThreadCount, prty, indent, "", name);
  1848.  
  1849.         V2_DisplayProcessTree (proc->pid, indent + 2, ps);
  1850.     }
  1851.     }
  1852. }
  1853.  
  1854. /*
  1855.  * Print the Process Tree
  1856.  */
  1857.  
  1858. int PrintProcessTree (pid_t pid)
  1859. {
  1860. #  if (OS_SIZE == OS_16)
  1861.     USHORT        rc;
  1862.  
  1863. /* Switch on release number */
  1864.  
  1865.     if (_osmajor < 20)
  1866.     {
  1867.     UCHAR            *pBuf = GetAllocatedSpace (0x2000);
  1868.     USHORT            count;
  1869.     V1ProcessStatus_t    pi;
  1870.  
  1871.     pi.M_Processes = pi.M_Modules = pi.N_Processes = pi.N_Modules = 0;
  1872.     pi.V1Processes = NULL;
  1873.     pi.V1Modules = NULL;
  1874.  
  1875.     if (pBuf == (UCHAR *)NULL)
  1876.         return 1;
  1877.  
  1878.     if (rc = Dos32QProcStatus (pBuf, 0x2000))
  1879.         return PrintWarningMessage ("jobs: DosQProcStatus failed\n%s",
  1880.                         GetOSSystemErrorMessage (rc));
  1881.  
  1882.     if (Parse_V1ProcessTable (pBuf, &pi))
  1883.        return 1;
  1884.  
  1885.     ReleaseMemoryCell ((void *)pBuf);
  1886.  
  1887.     qsort ((void *)pi.V1Processes, pi.N_Processes, sizeof (V1Process_t *),
  1888.         SortV1Processes);
  1889.  
  1890.         puts ("   PID  PPID TC Name     Program");
  1891.     PrintV1ProcessTree (pid, 0, &pi);
  1892.  
  1893.     for (count = 0; count < pi.N_Processes; count++)
  1894.         ReleaseMemoryCell ((void *)pi.V1Processes[count]);
  1895.  
  1896.     for (count = 0; count < pi.N_Modules; count++)
  1897.     {
  1898.         ReleaseMemoryCell ((void *)pi.V1Modules[count] -> modname);
  1899.         ReleaseMemoryCell ((void *)pi.V1Modules[count]);
  1900.     }
  1901.  
  1902.     ReleaseMemoryCell ((void *)pi.V1Processes);
  1903.     ReleaseMemoryCell ((void *)pi.V1Modules);
  1904.     }
  1905.  
  1906. /*
  1907.  * OS2 2.0 - grap space, get the information and display it
  1908.  */
  1909.  
  1910.     else
  1911. #  endif
  1912. #  if defined (__WATCOMC__)
  1913.     {
  1914.     int    res;
  1915.  
  1916.     if ((res = spawnlp (P_WAIT, "ps.exe", "ps", IntegerToString (pid),
  1917.                 (char *)NULL)) < 0)
  1918.         return PrintWarningMessage ("jobs: cannot find ps.exe\n");
  1919.  
  1920.     else if (res)
  1921.         return 1;
  1922.     }
  1923. #  else
  1924.     {
  1925.     V2ProcessStatus_t    *ps;
  1926.  
  1927.     if ((ps = GetProcessStatus ("jobs")) == (V2ProcessStatus_t *)NULL)
  1928.         return 1;
  1929.  
  1930.         puts ("   PID  PPID TC PRI  Program");
  1931.     V2_DisplayProcessTree (pid, 0, ps);
  1932.     ReleaseMemoryCell ((void *)ps);
  1933.     }
  1934. #  endif
  1935.     return 0;
  1936. }
  1937.  
  1938. /*
  1939.  * Get OS/2 2.x Process Structure
  1940.  */
  1941.  
  1942. static V2ProcessStatus_t * F_LOCAL GetProcessStatus (char *name)
  1943. {
  1944.     OSCALL_RET        rc;
  1945.     V2ProcessStatus_t    *ps;
  1946.  
  1947.     if ((ps = (V2ProcessStatus_t *)GetAllocatedSpace (0x8000))
  1948.         == (V2ProcessStatus_t *)NULL)
  1949.     return (V2ProcessStatus_t *)NULL;
  1950.  
  1951.     if ((rc = Dos32QProcStatus (ps, 0x8000)))
  1952.     {
  1953.     PrintWarningMessage ("%s: DosQProcStatus failed\n%s", name,
  1954.                  GetOSSystemErrorMessage (rc));
  1955.     return (V2ProcessStatus_t *)NULL;
  1956.     }
  1957.  
  1958.     return ps;
  1959. }
  1960. #endif
  1961.  
  1962. /*
  1963.  * A unix version of print process tree
  1964.  */
  1965.  
  1966. #if (OS_TYPE == OS_UNIX)
  1967. int PrintProcessTree (pid_t pid)
  1968. {
  1969.     return  system ("ps") ? PrintWarningMessage ("jobs: cannot find ps\n")
  1970.               : 0;
  1971. }
  1972. #endif
  1973.  
  1974. /*
  1975.  * A sort of times is available for OS/2. Not quite the complete UNIX
  1976.  * emulation, since it only reports current children.  However!
  1977.  * I think the times in the process structure are in 1/100th second.
  1978.  */
  1979.  
  1980. #if (OS_TYPE == OS_OS2) && (OS_SIZE == OS_32)
  1981. int PrintTimes (void)
  1982. {
  1983.     V2ProcessStatus_t    *ps;
  1984.     V2Process_t        *ppiLocal;
  1985.     V2Thread_t        *ptiCurrent;
  1986.     time_t        *Utime;
  1987.     time_t        *Stime;
  1988.     int            i;
  1989.     USHORT        pid = getpid ();
  1990.     time_t        tms_utime = 0;
  1991.     time_t        tms_stime = 0;
  1992.     time_t        tms_cutime = 0;
  1993.     time_t        tms_cstime = 0;
  1994.  
  1995. /* Initialise */
  1996.  
  1997.     if ((ps = GetProcessStatus ("times")) == (V2ProcessStatus_t *)NULL)
  1998.     return 1;
  1999.  
  2000. /* Scan the process tree */
  2001.  
  2002.     for (ppiLocal = ps->ppi;
  2003.      (ppiLocal->ulEndIndicator != PROCESS_END_INDICATOR);
  2004.          ppiLocal = (V2Process_t *) (ppiLocal->ptiFirst +
  2005.                       ppiLocal->usThreadCount))
  2006.     {
  2007.     if (ppiLocal->pidParent == pid)
  2008.     {
  2009.         Utime = &tms_cutime;
  2010.         Stime = &tms_cstime;
  2011.     }
  2012.  
  2013.     else if (ppiLocal->pid == pid)
  2014.     {
  2015.         Utime = &tms_utime;
  2016.         Stime = &tms_stime;
  2017.     }
  2018.  
  2019. /* If neither - skip */
  2020.  
  2021.     else
  2022.         continue;
  2023.  
  2024. /* Process threads */
  2025.  
  2026.     ptiCurrent = ppiLocal->ptiFirst;
  2027.  
  2028.     for (i = 0; i < ppiLocal->usThreadCount; i++, ptiCurrent++)
  2029.     {
  2030.         *Utime += ptiCurrent->ulUserTime;
  2031.         *Stime += ptiCurrent->ulSysTime;
  2032.     }
  2033.     }
  2034.  
  2035. /* Dump the info */
  2036.  
  2037.     printf ("%ldm%.2ld.%.2lds %ldm%ld.%.2lds\n",
  2038.         tms_utime / 6000L,  (tms_utime % 6000L) / 100L,  tms_utime % 100L,
  2039.         tms_stime / 6000L,  (tms_stime % 6000L) / 100L,  tms_stime % 100L);
  2040.     printf ("%ldm%.2ld.%.2lds %ldm%ld.%.2lds\n",
  2041.         tms_cutime / 6000L, (tms_cutime % 6000L) / 100L, tms_cutime % 100L,
  2042.         tms_cstime / 6000L, (tms_cstime % 6000L) / 100L, tms_cstime % 100L);
  2043.  
  2044.     return 0;
  2045. }
  2046. #endif
  2047.  
  2048. /* NT Version */
  2049.  
  2050. #if (OS_TYPE == OS_NT)
  2051. int PrintTimes (void)
  2052. {
  2053.     FILETIME    CreationTime;
  2054.     FILETIME    ExitTime;
  2055.     FILETIME    KernelTime;
  2056.     FILETIME    UserTime;
  2057.  
  2058.     if (!GetProcessTimes (0, &CreationTime, &ExitTime, &KernelTime, &UserTime))
  2059.     return PrintWarningMessage ("times: GetProcesTimes failed\n%s",
  2060.                     GetOSSystemErrorMessage (GetLastError ()));
  2061.     
  2062.     printf ("Kernel Time = %ld %ld\n", KernelTime.dwHighDateTime,
  2063.         KernelTime.dwLowDateTime);
  2064.     printf ("User Time   = %ld %ld\n", UserTime.dwHighDateTime,
  2065.         UserTime.dwLowDateTime);
  2066.  
  2067.     return 0;
  2068. }
  2069. #endif
  2070.  
  2071. /* UNIX Version */
  2072.  
  2073. #if (OS_TYPE == OS_UNIX)
  2074. int PrintTimes (void)
  2075. {
  2076.     struct tms        tms;
  2077.  
  2078.     times (&tms);
  2079.  
  2080.     printf ("%dm%.2d.%.2ds %dm%d.%.2ds\n%dm%.2d.%.2ds %dm%d.%.2ds\n",
  2081.         tms.tms_utime / (60L * (long)CLK_TCK),
  2082.           (tms.tms_utime % (60L * (long)CLK_TCK)) / (long)CLK_TCK,
  2083.           tms.tms_utime % (long)CLK_TCK,
  2084.         tms.tms_stime / (60L * (long)CLK_TCK),
  2085.           (tms.tms_stime % (60L * (long)CLK_TCK)) / (long)CLK_TCK,
  2086.           tms.tms_stime % (long)CLK_TCK,
  2087.         tms.tms_cutime / (60L * (long)CLK_TCK),
  2088.           (tms.tms_cutime % (60L * (long)CLK_TCK)) / (long)CLK_TCK,
  2089.           tms.tms_cutime % (long)CLK_TCK,
  2090.         tms.tms_cstime / (60L * (long)CLK_TCK),
  2091.           (tms.tms_cstime % (60L * (long)CLK_TCK)) / (long)CLK_TCK,
  2092.           tms.tms_cstime % (long)CLK_TCK);
  2093.  
  2094.     return 0;
  2095. }
  2096. #endif
  2097.  
  2098. /*
  2099.  * Specials for EMX
  2100.  */
  2101.  
  2102. #if defined (__EMX__) && (OS_TYPE == OS_OS2)
  2103. USHORT    Dos32GetPrty (USHORT usScope, PUSHORT pusPriority, USHORT pid)
  2104. {
  2105.     return ((USHORT)
  2106.         (_THUNK_PROLOG (2 + 4 + 2);
  2107.          _THUNK_SHORT (usScope);
  2108.          _THUNK_FLAT (pusPriority);
  2109.          _THUNK_SHORT (pid);
  2110.          _THUNK_CALL (Dos16GetPrty)));
  2111. }
  2112.  
  2113. USHORT    Dos32QProcStatus (PVOID pvProcData, USHORT usSize)
  2114. {
  2115.     return ((USHORT)
  2116.         (_THUNK_PROLOG (4 + 2);
  2117.          _THUNK_FLAT (pvProcData);
  2118.          _THUNK_SHORT (usSize);
  2119.          _THUNK_CALL (Dos16QProcStatus)));
  2120. }
  2121. #endif
  2122.